#ifndef _SCHEDULER_H
#define _SCHEDULER_H


#include "task.h"
#include "aceMesh_task.h"
#include "aceMesh_stack.h"
#include <stdlib.h>
#include "scheduler_common.h"

//#define LOCAL_MULTI_SIZE 4

#define SCHE_POLL_INTERVAL 500
#define LDM_DIRECTORY_SIZE 10
#define MAX_DIM 7
#define MAX_3d_BUF 10
#define MAX_2d_BUF 20


#define SEG_MASTER 1
#define SEG_SLAVE 0

#ifdef ACEMESH_PARA
#define MAXT 10000000
#define BUF_SIZE 2048
#endif

typedef struct generic_scheduler
{
  int id; 
#ifdef USE_STACK

  #if defined( _SERIAL_QUEUE)|| defined(_CIRCULAR_QUEUE)
    #ifdef LOCAL_MULTI_PRIORI
  struct aceMesh_stack private_queue[LOCAL_MULTI_SIZE]; 
    #else
  struct aceMesh_stack private_queue; 
    #endif

    #if defined( ASYN_INSERT_Q ) 
  struct concurrent_aceMesh_stack lower_private_queue;
    #endif
  #else
    #ifdef USE_PRIORITY_QUEUE
  struct concurrent_aceMesh_stack priority_queue;
    #endif
  struct concurrent_aceMesh_stack private_queue;
  #endif

  #ifdef MASTER
//#ifdef SEG_BUFF
//  struct aceMesh_stack master_private_queue;
//#else

    #ifdef LOCAL_MULTI_PRIORI
  struct concurrent_aceMesh_stack master_private_queue[LOCAL_MULTI_SIZE];
    #else
  struct concurrent_aceMesh_stack master_private_queue;
    #endif
//#endif
    #ifdef MPI_SURPPORT
//  struct concurrent_aceMesh_stack mpi_stack;
  struct aceMesh_queue blocking_queue;

      #ifdef MTEST_LIGHT
  struct mtest_queue mtest_blocking_queue;
      #endif  

    #endif

    #ifdef SEG_BUFF
// for slave thread, save master task which waiting for spawn by other slave
  struct concurrent_aceMesh_stack buff_spawn;
// for slave_agent and master, master task waitng for spawn
  struct concurrent_aceMesh_stack pending_spawn;
// for master thread, master task which waitng for sending to slave when cannot control pending_successor
  struct aceMesh_stack buff_successor;
// for master thread
  struct concurrent_aceMesh_stack pending_successor;
    #endif


  #endif

#endif
}generic_scheduler;

#ifdef LDMM
struct dtile_Info
{
  int ldm_array_id; 
  void* mem_addr;
  int tileno[3];
  int wr_info;
  int pre_loop_id;
};
typedef struct region
{
    void* mem_addr;
    int loop_id;
    short wr;
    short ndim;
    short tileno[MAX_DIM];
}region_3d, region_2d;

typedef struct slot
{
    short slot_id;
    //struct region *info;
    region_3d *info;
}slot3d,slot2d;
#endif

#ifdef USE_SHARED_STACK
static concurrent_aceMesh_stack shared_queue;
#endif

void slave_local_spawn(generic_scheduler *my_scheduler,struct task* t);  
void slave_scheduler_enqueue(struct task* t); 
void slave_spawn_to_id(struct task* t);
void *slave_worker_kernel_func();
#ifdef LDMM
void slave_ldm_postreq_tile(void* mem_addr, int ndim, int *tileno, int wr_info);
void slave_ldm_postreq_tile_2d(void* mem_addr, int ndim, int *tileno, int wr_info);
void slave_ldm_getreq_tile( int *ldm_varno, int *ldm_reuse);
void slave_ldm_getreq_tile_2d( int *ldm_varno, int *ldm_reuse);
#endif
void local_spawn(generic_scheduler *my_scheduler,struct task* t); 
#ifdef MASTER 
void local_spawn_master(generic_scheduler *my_scheduler,struct task* t);
#endif  
void init_spawn_sche(struct task* t); 
void wait_for_all();
void create_worker_thread_p(int n_threads, int p[]);
void main_kernel_func(struct task* p);
#endif
